//go:build windows

package onet

import (
	"github.com/panjf2000/gnet"
	"net"
)

type DummyCodec struct{}

func (n *DummyCodec) Encode(_ gnet.Conn, buf []byte) (out []byte, err error) {
	return buf, nil
}

func (n *DummyCodec) Decode(c gnet.Conn) (out []byte, err error) {
	if c.BufferLength() == 0 {
		return nil, nil // out = nil 表示结束, gnet 不会调用 React
	}
	return []byte{}, nil // out != nil, gnet 会调用 React
}

type conn struct {
	c gnet.Conn
}

func (c conn) Next(n int) (buf []byte, err error) {
	_, buf = c.c.ReadN(n)
	c.c.ShiftN(n)
	return
}

func (c conn) Peek(n int) (buf []byte, err error) {
	_, buf = c.c.ReadN(n)
	return
}

func (c conn) Discard(n int) (discarded int, err error) {
	return c.c.ShiftN(n), nil
}

func (c conn) InboundBuffered() (n int) {
	return c.c.BufferLength()
}

func (c conn) AsyncWrite(buf []byte) (err error) {
	return c.c.AsyncWrite(buf)
}

func (c conn) OutboundBuffered() (n int) {
	return 0
}

func (c conn) Close() error {
	return c.c.Close()
}

func (c conn) Context() (ctx any) {
	return c.c.Context()
}

func (c conn) SetContext(ctx any) {
	c.c.SetContext(ctx)
}

func (c conn) LocalAddr() (addr net.Addr) {
	return c.c.LocalAddr()
}

func (c conn) RemoteAddr() (addr net.Addr) {
	return c.c.RemoteAddr()
}

type GnetEventHandler struct {
	*gnet.EventServer
	eventHandler EventHandler
}

func NewGnetEventHandler(eventHandler EventHandler) *GnetEventHandler {
	return &GnetEventHandler{eventHandler: eventHandler}
}

func (eh *GnetEventHandler) OnOpened(c gnet.Conn) (out []byte, action gnet.Action) {
	eh.eventHandler.OnOpen(&conn{c: c})
	return
}

func (eh *GnetEventHandler) OnClosed(c gnet.Conn, err error) (action gnet.Action) {
	// simplify error message
	if opErr, ok := err.(*net.OpError); ok {
		err = opErr.Err
	}
	eh.eventHandler.OnClose(&conn{c: c}, err)
	return
}

func (eh *GnetEventHandler) React(_ []byte, c gnet.Conn) (out []byte, action gnet.Action) {
	eh.eventHandler.OnData(&conn{c: c})
	return
}

func Run(eventHandler EventHandler, protoAddr string, opts ...gnet.Option) (err error) {
	opts = append(opts, gnet.WithCodec(&DummyCodec{}))
	return gnet.Serve(NewGnetEventHandler(eventHandler), protoAddr, opts...)
}
